import 'dart:io';
import 'dart:convert';
import 'package:dio/io.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import '../../../app/utils/networking/result_analyzed.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
export '../../../app/utils/networking/result_analyzed.dart';

typedef RequestResult = Future<ResponseAnalyzed>;
typedef ResponseObject = Map<dynamic, dynamic>;

const httpAppVersion = '1.0.0';
const httpBuildVersion = 'build1';

enum HttpMethod {get, post, getBody, postBody}

const _timeout = Duration(seconds: 30);
Map<String, dynamic>? _baseParam = {};
bool _log = false;

class HttpManager {
  final Dio _dio = Dio(BaseOptions(connectTimeout: _timeout, receiveTimeout: _timeout));
  HttpManager._privateConstructor();
  Dio get dio => _dio;
  static final HttpManager instance = HttpManager._privateConstructor();
  static setHeaders(Map<String, dynamic>? headers) {
    HttpManager.instance._dio.options.headers.addAll(headers!);
  }
  static baseUrl(String baseUrl) {
    final url = baseUrl.endsWith("/") ? baseUrl : "$baseUrl/";
    HttpManager.instance._dio.options.baseUrl = url;
  }
  static setBaseParam(Map<String, dynamic>? param) {
    _baseParam = param;
  }
  static setEnableLog(bool enable) {
    _log = enable;
  }

  /// 安装客户端适配器
  /// proxy all http to localhost:8888
  static setProxy(String host, String port) {
    // 配置代理
    HttpManager.instance._dio.httpClientAdapter = IOHttpClientAdapter(
      createHttpClient: () {
        final client = HttpClient();
        client.badCertificateCallback = (cert, host, port) {
          return true; // 信任证书
        };
        if (host.isNotEmpty && port.isNotEmpty) {
          client.findProxy = (uri) {
            // 将请求代理至 localhost:8888。
            // 请注意，代理会在你正在运行应用的设备上生效，而不是在宿主平台生效。
            return "PROXY $host:$port"; // 设置代理地址
          };
        }
        return client;
      },
    );
  }

  /// 请求
  static Future<Response?> request(HttpMethod method, String url, {Map<String, dynamic>? params}) async {
    try{
      Map<String, dynamic>? params2 = {};
      params2.addAll(params??{});
      if (_baseParam != null) { params2.addAll(_baseParam!); }
      if (_log) debugPrint("====================================================");
      var baseUrl = HttpManager.instance._dio.options.baseUrl;
      var meth = method.toString().substring(11, method.toString().length);
      var token = HttpManager.instance._dio.options.headers["UserToken"];
      if (_log) debugPrint('请求地址：$baseUrl${url.replaceFirst("/", "")}');
      if (_log) debugPrint('请求方式：$meth');
      if (_log) debugPrint("开始请求：${DateTime.now().toString()}");
      Response? response = await _sendRequest(method, url, params2);
      // response = await _sendRequest(method, url, params);
      if (_log) debugPrint("结束请求：${DateTime.now().toString()}");
      if (_log) debugPrint('UserToken：$token');
      if (_log) debugPrint('请求参数：${jsonEncode(params2)}');
      if (_log) debugPrint("响应数据：$response");
      if (_log) debugPrint("====================================================");
      // Clipboard.setData(ClipboardData(text: _response.toString())); // 直接复制JSON
      // LogUtil.e('LogUtil.e _response = $_response');
      return response;
    }on DioException catch(e) {
      return _dioError(e);
    }
  }


  /// 请求并解析
  static Future<ResponseAnalyzed> requestAnalyzing(HttpMethod method, String url, {Map<String, dynamic>? params, Type? className}) async {
    var response = await request(method, url, params: params);
    ResponseAnalyzed result = await ResponseAnalyzed.analyzingAndCheckup(response);
    return result;
  }

  /// 上传数据
  static Future<Response?> upload(HttpMethod method, String url, Map<String, dynamic>? params, FormData formData) async {
    Dio dio = HttpManager.instance._dio;
    try{
      Map<String, dynamic>? params2 = {};
      params2.addAll(params??{});
      if (_baseParam != null) { params2.addAll(_baseParam!); }
      if (_log) debugPrint("====================================================");
      var baseUrl = HttpManager.instance._dio.options.baseUrl;
      var meth = method.toString().substring(11, method.toString().length);
      var token = HttpManager.instance._dio.options.headers["UserToken"];
      if (_log) debugPrint('请求地址：$baseUrl${url.replaceFirst("/", "")}');
      if (_log) debugPrint('请求方式：$meth');
      if (_log) debugPrint("开始上传：${DateTime.now().toString()}");
      Response? response = await dio.post(
        url, data: formData, queryParameters: _baseParam,
        options: Options(contentType: Headers.jsonContentType),
      );
      if (_log) debugPrint("上传结束：${DateTime.now().toString()}");
      if (_log) debugPrint('UserToken：$token');
      if (_log) debugPrint('请求参数：$_baseParam');
      if (_log) debugPrint('请求表单：${formData.toString()}');
      if (_log) debugPrint("响应数据：$response");
      if (_log) debugPrint("====================================================");
      return response;
    }on DioException catch(e) {
      return _dioError(e);
    }
  }

  /// 上传数据
  static Future<ResponseAnalyzed> uploadAnalyzing(HttpMethod method, String url, Map<String, dynamic>? params, FormData formData) async {
    var response = await upload(method, url, params, formData);
    ResponseAnalyzed result = await ResponseAnalyzed.analyzingAndCheckup(response);
    return result;
  }


  static Future uploadStream(HttpMethod method, String url, Stream stream) async {
    Dio dio = HttpManager.instance._dio;
    // final postData = <int>[0, 1, 2];
    // 构建 Stream<List<int>>
    // Stream data = Stream.fromIterable(postData.map((e) => [e]));
    await dio.post(url, data: stream, options: Options(
        headers: {
          Headers.contentLengthHeader: stream.length
        }),
    );
  }




  /// 发送网络请求
  static Future<Response?> _sendRequest(HttpMethod method, String url, Map<String, dynamic>? params) async {
    Dio dio = HttpManager.instance._dio;
    try {
      switch(method) {
        case HttpMethod.get:
          return await dio.get(url, options: Options(contentType: Headers.jsonContentType));
        case HttpMethod.post:
          return await dio.post(url, data: jsonEncode(params), options: Options(contentType: Headers.jsonContentType));
        case HttpMethod.getBody:
          return await dio.get(url, queryParameters: params, options: Options(contentType: Headers.jsonContentType));
        case HttpMethod.postBody:
          return await dio.post(url, data: jsonEncode(params), options: Options(contentType: Headers.formUrlEncodedContentType));
        default:
          throw Exception("请求方式错误");
      }
    } on DioException catch (e) {
      return _dioError(e);
    }
  }

  /// 处理错误信息
  static Response? _dioError(DioException e) {
    Response response = Response(requestOptions: RequestOptions());
    response.data = {};
    response.data["code"] = "1000";
    response.data["data"] = "";
    switch(e.type) {
      case DioExceptionType.connectionTimeout:
        response.data["message"] = '网络连接超时';
      case DioExceptionType.sendTimeout:
        response.data["message"] = '网络请求超时';
      case DioExceptionType.receiveTimeout:
        response.data["message"] = '网络响应超时';
      case DioExceptionType.badResponse:
        response.data["message"] = '网络请求异常';
      case DioExceptionType.cancel:
        response.data["message"] = '网络请求取消';
      case DioExceptionType.unknown:
        response.data["message"] = '未知错误,请检查网络或重新刷新';
      default:
        response.data["message"] = '未知错误,请检查网络或重新刷新';
    }
    debugPrint('dio异常error.response = ${e.response}');
    return response;
  }

  /// 将图片路径的数组转换成 MultipartFile 数组，方便直接使用 FormData
  static Future<List<MultipartFile>> imageFiles(List imagePath) async {
    List<MultipartFile> files = [];
    for (var path in imagePath) {
      String? jpegPath = await HttpManager.convertImageToJpeg(path);
      final fileName = path.split('/').last.replaceAll('.heic', '.jpeg');
      files.add(await MultipartFile.fromFile(jpegPath!, filename: fileName));
    }
    return files;
  }

  /// 将.heic格式的图片转换成.jpeg格式的图片
  static Future<String?> convertImageToJpeg(String? imagePath) async {
    if (imagePath != null && imagePath.isNotEmpty && imagePath.toLowerCase().endsWith('.heic')) {
      File imageFile = File(imagePath);
      final imageBytes = await imageFile.readAsBytes();
      List<int> compressedImageBytes = await FlutterImageCompress.compressWithList(
        imageBytes,
        quality: 90,
        format: CompressFormat.jpeg,
      );
      String directory = path.dirname(imagePath);
      String fileName = path.basenameWithoutExtension(imagePath);
      String newPath = path.join(directory, '$fileName.jpeg');
      File convertedImage = File(newPath);
      await convertedImage.writeAsBytes(compressedImageBytes);
      return convertedImage.path;
    }
    XFile? file = await ImageTool.imageCompressAndGetFile(File(imagePath!));
    return file?.path;
  }
}



class ImageTool {
  /// 图片压缩 File -> File
  static Future<XFile?> imageCompressAndGetFile(File file) async {
    if (file.lengthSync() < 200 * 1024) {
      return XFile(file.path);
    }
    var quality = 100;
    if (file.lengthSync() > 4 * 1024 * 1024) {
      quality = 50;
    } else if (file.lengthSync() > 2 * 1024 * 1024) {
      quality = 60;
    } else if (file.lengthSync() > 1 * 1024 * 1024) {
      quality = 70;
    } else if (file.lengthSync() > 0.5 * 1024 * 1024) {
      quality = 80;
    } else if (file.lengthSync() > 0.25 * 1024 * 1024) {
      quality = 90;
    }

    // path_provider
    // 获取临时目录路径： getTemporaryDirectory()
    // 获取应用程序文档目录路径： getApplicationDocumentsDirectory()
    // 获取外部存储目录路径（Android）： getExternalStorageDirectory()
    Directory tempDir = await getTemporaryDirectory();
    // Directory appDocDir = await getApplicationDocumentsDirectory();
    var targetPath = "${tempDir.absolute.path}/${DateTime.now().millisecondsSinceEpoch}.jpg";

    XFile? result = await FlutterImageCompress.compressAndGetFile(
      file.absolute.path,
      targetPath,
      minWidth: 600,
      quality: quality,
      rotate: 0,
    );
    // print("压缩后：${file.lengthSync() / 1024}");
    // print("压缩后：${File(result!.path).lengthSync() / 1024}");
    return result;
  }

  /// 图片压缩 File -> Uint8List
  static Future<Uint8List?> imageCompressFile(File file) async {
    var result = await FlutterImageCompress.compressWithFile(
      file.absolute.path,
      minWidth: 2300,
      minHeight: 1500,
      quality: 94,
      rotate: 90,
    );
    // print(file.lengthSync());
    // print(result?.length);
    return result;
  }

  /// 图片压缩 Asset -> Uint8List
  static Future<Uint8List?> imageCompressAsset(String assetName) async {
    var list = await FlutterImageCompress.compressAssetImage(
      assetName,
      minHeight: 1920,
      minWidth: 1080,
      quality: 96,
      rotate: 180,
    );
    // print(list?.length);
    return list;
  }

  /// 图片压缩 Uint8List -> Uint8List
  static Future<Uint8List> testComporessList(Uint8List list) async {
    var result = await FlutterImageCompress.compressWithList(
      list,
      minHeight: 1024,
      minWidth: 768,
      quality: 96,
      // rotate: 135,
    );
    // print(list.length);
    // print(result.length);
    return result;
  }
}